package virtorina.server.domain;

import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import virtorina.server.PMF;

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Question implements Serializable {
	private static final long serialVersionUID = 1L;
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Long ID;
	@Persistent
	private String question;
	@Persistent
	private LinkedList<String> answers;
	@Persistent
	private Integer NumOfRank;
	@Persistent
	private Double rank;
	@Persistent
	private Integer NumOfComplexity;
	@Persistent
	private Double Complexity;
	@Persistent
	private Integer iterations;
	@Persistent
	private Boolean checked;
	@Persistent
	private Double rnd;
	@Persistent
	private Long author;
	@Persistent
	private String provider;
	@Persistent
	private Integer NumOfComplaint;
	/*
	 * 0 - текст 1 - картинка 2 - Аудио 3 - мап
	 */
	@Persistent
	private Integer type;
	@Persistent
	private Long duration;
	@NotPersistent
	private long time;
	@NotPersistent
	private LinkedList<String> LabelsNames;
	@NotPersistent
	private String authorName;

	public LinkedList<String> getLabelsNames() {
		if (LabelsNames == null) {
			LabelsNames = Label.getLabelsNames(QuestionLabel.getLabelsID(ID));
		}
		return LabelsNames;
	}

	public void setLabelsNames(LinkedList<String> labelsNames) {
		LabelsNames = labelsNames;
	}

	public void setLabelsNamesFromIDs(LinkedList<Long> LabelIDs) {
		LabelsNames = Label.getLabelsNames(LabelIDs);
	}

	public Question(String question, LinkedList<String> answers, Long author,
			Integer type, String provider, Integer time2) {
		this.question = question;
		this.answers = answers;
		this.author = author;
		this.type = type;
		this.provider = provider;
		this.duration = new Long(time2 * 1000);
		this.rank = 2.5;
		this.iterations = 0;
		this.Complexity = 0.0;
		this.NumOfComplexity = 0;
		this.NumOfRank = 0;
		this.checked = false;
		this.rnd = new Random().nextDouble();
		this.NumOfComplaint = 0;
	}

	public Long getID() {
		return ID;
	}

	public void setID(Long iD) {
		ID = iD;
	}

	public String getQuestion() {
		return question;
	}

	public void setQuestion(String question) {
		this.question = question;
	}

	public LinkedList<String> getAnswer() {
		if (answers instanceof org.datanucleus.sco.backed.LinkedList) {
			answers = new LinkedList<String>(answers);
		}
		return answers;
	}

	public void setAnswer(LinkedList<String> answer) {
		this.answers = answer;
	}

	public Double getRank() {
		return rank;
	}

	public void setRank(Double rank) {
		this.rank = rank;
	}

	public static void saveQuestions(LinkedList<Question> tq) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.makePersistentAll(tq);
		pm.close();
	}

	public static void saveQuestion(Question tq) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.makePersistent(tq);
		pm.close();
	}

	public static Long addQuestionAndLabels(Question q,
			LinkedHashSet<String> labels) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Question qu = null;
		System.out.println("test");
		if (q.getID() != null) {
			System.out.println(q.getID());
			qu = null;
			try {
				qu = pm.getObjectById(Question.class, q.getID());
			} catch (Exception exp) {
				pm.close();
				return -1L;
			}
		}
		LinkedList<Long> LIds = new LinkedList<Long>();
		Query query = pm.newQuery("select from " + Label.class.getName()
				+ " where name == nm");
		query.declareParameters("String nm");
		List<Label> res;
		Label t;
		for (String s : labels) {
			res = (List<Label>) query.execute(s);
			if (res.isEmpty()) {
				LIds.add(Label.saveLabel(s));
			} else {
				t = res.get(0);
				if (q.getID() == null) {
					t.incCount();
					pm.makePersistent(t);
				}
				LIds.add(t.getID());
			}
		}
		if (q.getID() != null) {
			qu.changeQuestion(q);
			pm.makePersistent(qu);
			query = pm.newQuery("select from " + QuestionLabel.class.getName()
					+ " where QuestionID == qID");
			query.declareParameters("Long qID");
			// возвращем существующие связки
			List<QuestionLabel> rslt = (List<QuestionLabel>) query.execute(q
					.getID());
			// удаляем из списка на новые связи - существующие
			// удаляем более не существующие связи, декрементим лейблы
			LinkedList<Long> toDec = new LinkedList<Long>();
			for (QuestionLabel qt : rslt) {
				if (LIds.remove(qt.getLabelID())) {
				} else {
					toDec.add(qt.getLabelID());
					pm.deletePersistent(qt);
				}
			}
			if (!toDec.isEmpty()) {
				query = pm.newQuery(Label.class, ":p.contains(ID)");
				List<Label> decLabels = (List<Label>) query.execute(toDec);
				for (Label lab : decLabels) {
					lab.decCount();
				}
				pm.makePersistentAll(decLabels);
			}
			if (!LIds.isEmpty()) {
				query = pm.newQuery(Label.class, ":p.contains(ID)");
				List<Label> decLabels = (List<Label>) query.execute(LIds);
				for (Label lab : decLabels) {
					lab.incCount();
				}
				pm.makePersistentAll(decLabels);
			}
		} else {
			q = pm.makePersistent(q);
		}
		LinkedList<QuestionLabel> ql = new LinkedList<QuestionLabel>();
		for (Long LId : LIds) {
			ql.add(new QuestionLabel(q.getID(), LId));
		}
		pm.makePersistentAll(ql);
		pm.close();
		return q.getID();
	}

	public static Question getByID(Long id) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Question q;
		System.out.println("id = " + id);
		try {
			q = (Question) pm.getObjectById(Question.class, id);
		} catch (JDOObjectNotFoundException e) {
			System.out.println("fail");
			q = null;
		}
		pm.close();
		return q;
	}

	public void changeQuestion(Question q) {
		this.answers = q.getAnswer();
		this.author = q.getAuthor();
		this.provider = q.getProvider();
		this.question = q.getQuestion();
		this.duration = q.getDuration();
		this.type = q.getType();
	}

	public static void updQuestion(Question tq) {
		Integer iter = tq.getIterations();
		if (iter == null) {
			tq.setIterations(1);
		} else {
			tq.setIterations(iter + 1);
		}
		tq.setRnd(new Random().nextDouble());
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.makePersistent(tq);
		pm.close();
	}

	public static LinkedList<Long> getIdsByLabels(LinkedList<Long> Labels) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(QuestionLabel.class, ":p.contains(LabelID)");
		List<QuestionLabel> qls = (List<QuestionLabel>) query.execute(Labels);
		LinkedList<Long> rslt = new LinkedList<Long>();
		for (QuestionLabel ql : qls) {
			rslt.add(ql.getQuestionID());
		}
		pm.close();
		return rslt;
	}

	public static int numOfQuestions(LinkedList<Long> labels,
			LinkedList<Integer> types) {
		LinkedList<Long> qw = getIdsByLabels(labels);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		for (int i : types) {
			System.out.println(i);
		}
		List<Question> qls = null;
		if (qw.size() != 0) {
			Query query = pm.newQuery(Question.class,
					":p.contains(ID) && :t.contains(type)");
			qls = (List<Question>) query.execute(qw, types);
			;
		} else {
			Query query = pm.newQuery(Question.class, ":t.contains(type)");
			qls = (List<Question>) query.execute(types);
		}
		int rslt = qls.size();
		pm.close();
		return rslt;
	}

	public static Question getRandomQuestion(LinkedList<Long> labels,
			LinkedList<Integer> types, Long last) {
		if (last == null) {
			last = -1L;
		}
		LinkedList<Long> qw = null;
		if (!labels.isEmpty()) {
			qw = getIdsByLabels(labels);
		}

		// query = pm.newQuery(Label.class, ":p.contains(ID)");
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<Question> rslt = null;
		Question tq = null;
		int iterat = 0;

		if (!labels.isEmpty()) {
			qw.remove(last);
		}
		Query q = pm.newQuery(Question.class);
		q.setFilter("rnd > random && t.contains(type)");
		q.declareParameters("Double random, java.util.LinkedList t");
		q.setOrdering("rnd ASC");
		a: while (true) {
			rslt = (List<Question>) q.execute(new Random().nextDouble(), types);
			if (!rslt.isEmpty()) {
				for (Question qu : rslt) {
					if (qu.getID().equals(last)) {
						continue;
					}
					if (!labels.isEmpty()) {
						if (qw.contains(qu.getID())) {
							tq = qu;
							break a;
						}
					} else {
						tq = qu;
						break a;
					}
				}
			}
			System.out.println(++iterat + " iterations");
		}
		if (tq.getDuration() == null) {
			tq.setDuration(20000L);
		}
		pm.close();
		System.out.println("выбрали " + tq.getID());
		return tq;
	}

	public Integer getIterations() {
		return iterations;
	}

	public void setIterations(Integer iterations) {
		this.iterations = iterations;
	}

	public Integer getNumOfRank() {
		return NumOfRank;
	}

	public void setNumOfRank(Integer numOfRank) {
		NumOfRank = numOfRank;
	}

	public boolean isCheked() {
		return checked;
	}

	public void setCheked(boolean cheked) {
		checked = cheked;
	}

	public long getTime() {
		return time;
	}

	public void setTime(long Time) {
		this.time = Time;
	}

	public Double getRnd() {
		return rnd;
	}

	public Boolean getChecked() {
		return checked;
	}

	public void setChecked(Boolean checked) {
		this.checked = checked;
	}

	public void setRnd(Double rnd) {
		this.rnd = rnd;
	}

	public Long getAuthor() {
		return author;
	}

	public void setAuthor(Long author) {
		this.author = author;
	}

	public Integer getType() {
		if (type == null) {
			type = 0;
		}
		return type;
	}

	public void setType(Integer type) {
		this.type = type;
	}

	public Integer getNumOfComplaint() {
		return NumOfComplaint;
	}

	public void setNumOfComplaint(Integer numOfComplaint) {
		NumOfComplaint = numOfComplaint;
	}

	public Integer getNumOfСomplexity() {
		return NumOfComplexity;
	}

	public void setNumOfСomplexity(Integer numOfСomplexity) {
		NumOfComplexity = numOfСomplexity;
	}

	public Double getComplexity() {
		return Complexity;
	}

	public void setComplexity(Double Complexity) {
		this.Complexity = Complexity;
	}

	public Long getDuration() {
		if (duration == null) {
			duration = 20000L;
		}
		return duration;
	}

	public void setDuration(Long duration) {
		this.duration = duration;
	}

	public LinkedList<Long> getLabelsID() {
		return QuestionLabel.getLabelsID(this.ID);
	}

	public String getProvider() {
		return provider;
	}

	public void setProvider(String provider) {
		this.provider = provider;
	}

	public void setAuthorName(String author) {
		this.authorName = author;
	}

	public String getAuthorName() {
		if (this.authorName == null) {
			Long a = getAuthor();
			if (a == null) {
				return "Anonymous";
			} else {
				this.authorName = User.getUser(getAuthor()).getName();
			}
		}
		return this.authorName;
	}

}
